use crate::config::db_conn::get_db;
use crate::entity::long_term_goals::{ActiveModel, Entity};
use crate::entity::task_info;
use crate::util::time_util::{get_date_from_timestamp, get_sec_timestamp_by_str};
use sea_orm::ActiveValue::Set;
use sea_orm::{
    ColumnTrait, Condition, DeriveColumn, EntityTrait, EnumIter, QueryFilter, QuerySelect,
};
use serde::{Deserialize, Serialize};
use tauri::command;
use uuid::Uuid;

#[derive(Debug, Serialize, Deserialize, Default, Clone)]
pub struct GoalsDto {
    pub no: Option<String>,
    pub name: String,
    pub desc: String,
    pub start_time: String,
    pub count_tomato: Option<i64>,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
enum QueryAs {
    GoalsNo,
    CostTomato,
}

#[command]
pub(crate) async fn add_goals(goals: GoalsDto) {
    let uuid = Uuid::new_v4().to_string();

    let ts = get_sec_timestamp_by_str(goals.start_time.as_str());

    let model = ActiveModel {
        id: Default::default(),
        no: Set(uuid),
        name: Set(goals.name),
        desc: Set(goals.desc),
        start_time: Set(ts),
        cash_tomato: Default::default(),
    };

    Entity::insert(model)
        .exec(get_db().expect("get the db connection failed"))
        .await
        .unwrap();
}

#[command]
pub(crate) async fn query_goals() -> Vec<GoalsDto> {
    let condi = Condition::all();

    let temp_vec = Entity::find()
        .filter(condi)
        .all(get_db().expect("get the db connection failed"))
        .await
        .unwrap_or_else(|e| {
            tracing::error!("{:?}", e);
            // return empty vec
            Vec::new()
        });

    let mut task_list = Vec::<GoalsDto>::new();

    for x in temp_vec {
        let x1 = GoalsDto {
            no: Some(x.no),
            name: x.name,
            desc: x.desc,
            start_time: get_date_from_timestamp(x.start_time),
            count_tomato: x.cash_tomato,
        };

        task_list.push(x1);
    }

    task_list
}

#[command]
pub(crate) async fn query_goals_details() -> Vec<GoalsDto> {
    let condi = Condition::all();

    let temp_vec = Entity::find()
        .filter(condi)
        .all(get_db().expect("get the db connection failed"))
        .await
        .unwrap_or_else(|e| {
            tracing::error!("{:?}", e);
            // return empty vec
            Vec::new()
        });

    let mut task_list = Vec::<GoalsDto>::new();

    let res: Vec<(String, i64)> = task_info::Entity::find()
        .select_only()
        .column_as(task_info::Column::Type, QueryAs::GoalsNo)
        .column_as(task_info::Column::CashTomato.count(), QueryAs::CostTomato)
        .group_by(task_info::Column::Type)
        .into_values::<_, QueryAs>()
        .all(get_db().expect("get the db connection failed"))
        .await
        .unwrap();

    for x in temp_vec {
        let option = res.iter().find(|(key, num)| key.as_str() == x.no);

        let mut cash_tomato = 0;
        if option.is_some() {
            cash_tomato = option.unwrap().1;
        }

        let x1 = GoalsDto {
            no: Some(x.no.clone()),
            name: x.name,
            desc: x.desc,
            start_time: get_date_from_timestamp(x.start_time),
            count_tomato: Some(cash_tomato),
        };

        task_list.push(x1);
    }

    task_list
}
